﻿using System;
using System.Diagnostics;
using System.Globalization;

using Atomic.Libraries;

namespace Atomic.Structures
{
	/// <summary>
	/// Represents a spin-polarized atom by allowing a magnetic moment to be assigned.
	/// </summary>
	[Serializable]
	[DebuggerDisplay("{Symbol}")]
	public class SpinPolarizedAtom : Atom
	{
		[NonSerialized] private int hashCode;
		[NonSerialized] private string symbol;

		public SpinPolarizedAtom(Atom baseAtom, double magneticMoment)
		{
			if (baseAtom is SpinPolarizedAtom)
			{
				throw new ArgumentException("Nesting of spin-polarized atoms isn't allowed.");
			}

			BaseAtom = baseAtom;
			MagneticMoment = magneticMoment;
		}

		public override Atom SpinUnpolarize()
		{
			return BaseAtom;
		}

		public override bool Equals(Atom other)
		{
			return Equals(other as SpinPolarizedAtom);
		}

		public bool Equals(SpinPolarizedAtom other)
		{
			if (object.ReferenceEquals(other, null))
			{
				return false;
			}

			return EqualityHelper.Equals(this, other, new object[] { BaseAtom, MagneticMoment }, new object[] { other.BaseAtom, other.MagneticMoment }, hashCode, other.hashCode);
		}

		public override int GetHashCode()
		{
			if (hashCode == 0)
			{
				hashCode = EqualityHelper.HashCode(new object[] { BaseAtom, MagneticMoment });
			}

			return hashCode;
		}

		public Atom BaseAtom
		{
			get;
			private set;
		}

		public double MagneticMoment
		{
			get;
			private set;
		}

		public override int Number
		{
			get
			{
				return BaseAtom.Number;
			}
		}

		public override string Symbol
		{
			get
			{
				if (symbol == null)
				{
					symbol = MagneticMoment.ToString("r", CultureInfo.InvariantCulture);
					if (!symbol.StartsWith("-"))
					{
						symbol = "+" + symbol;
					}
					symbol = BaseAtom.Symbol + symbol;
				}

				return symbol;
			}
		}

		public override double Mass
		{
			get
			{
				// Not defined for this pseudo-atom.
				return BaseAtom.Mass;
			}
		}

		public override string ElectronConfiguration
		{
			get
			{
				// Probably changed in a very delicate way.
				throw new NotSupportedException();
			}
		}
	}
}
